<?php
/**
 * TeamPlayers.class.php
 *
 * PHP version 5
 *
 * Copyright (c) 2010, Leo Valen  http://www.leovalen.no
 * All rights reserved.
 *
 * @author		Leo Valen <leo@code.coop>
 */
namespace TeamPlayers;
$start_time = microtime( true );
require 'Object.class.php';
require 'StoredObject.class.php';
require 'AccessControlledObject.class.php';
require 'TestObject.class.php';
require 'AccessControl.class.php';
require 'Mysqli.class.php';
require 'Controller.class.php';
require_once("lib/php/Smarty-3.1.7/Smarty.class.php");
require 'iCalcreator.class.php';
require_once('classes/Settings.class.php');
require_once('classes/Ajaxtools.class.php');
require('controllers/baseController.php');

/**
 * Principal class for TeamPlayers systems
 *
 * The TeamPlayers class parses the URI and determines which controller to use for
 * handling the request, and instantiates the controller.
 *
 * @version		1.0
 * @todo remove routing from this class, this is handled by the separate router class
 */
class TeamPlayers
{
    /**
     * The single instance of self
     *
     * @var object
     * @access private
     * @static
     */
    private static $instance;
    /**
	 * Smarty instance
	 *
	 * @var object
	 * @access public
	 * @static
	 */
    public static $smarty;
    /**
     * TeamPlayersMysqli instance
     *
     * @var object
     * @access public
     * @static
     */
	public static $db;
	/**
	 * AccessControl instance
	 *
	 * @var object
	 * @access public
	 * @static
	 */
	public static $ac;
	/**
	 * Controller instance
	 *
	 * @var object
	 * @access public
	 * @static
	 */
	public static $controller;
	/**
	 * Request URI
	 *
	 * @var string
	 * @access public
	 * @static
	 */
	public static $request_uri;
	/**
	 * URI element stack
	 *
	 * @var array
	 * @access public
	 * @static
	 */
	public static $stack;
	/**
	 * Initializes shared objects
	 *
	 * @return		void
	 * @access		public
	 */
	
	/**
	 * 
	 * Holds the settings object
	 * @var object
	 */
	public static $settings;
	
	/**
	 * 
	 * "Ajax tools" - stuff thats handy for web 2 point 0 - o rama and other buzzwords
	 * @var Object
	 */
	public static $axt;
	
	public function __construct ()
	{
	    setlocale( LC_ALL, TeamPlayersDefaultLocale );
		date_default_timezone_set( TeamPlayersDefaultTimezone );
		set_include_path( get_include_path() . PATH_SEPARATOR . dirname( $_SERVER['SCRIPT_FILENAME'] )
		        . PATH_SEPARATOR . '../configurations'
				. PATH_SEPARATOR . dirname( $_SERVER['SCRIPT_FILENAME'] ) . '/lib'
				. PATH_SEPARATOR . dirname( $_SERVER['SCRIPT_FILENAME'] ) . '/classes' );
		
		self::$db = new \TeamPlayers\mysqli();
		self::$ac = new AccessControl();
		self::$settings = new Settings();
		self::$axt = new AjaxTools();
		
		self::$smarty = new \Smarty();
		self::$smarty->assign( 'ac', TeamPlayers::$ac );
		self::$smarty->debugging = true;
		
		
		self::$ac->authenticateFromUserInput();
		self::$smarty->assign("authenticated", self::$ac->authenticated);
		$this->populateSmartyFromConfig();
		
	}
	
	private function populateSmartyFromConfig(){
		self::$smarty->assign( 'organizationName', self::$settings->organizationName);
		self::$smarty->assign( 'aboutOrganization', self::$settings->organizationDescription);
		self::$smarty->assign( 'facebookLink', self::$settings->facebookLink);
		
	if(TeamPlayers::$ac->hasRole("SystemAdministrator")){
			self::$smarty->assign( 'SystemAdministrator', true);
		}
		
	}
	
	/**
	 * Returns the single instance of self
	 *
	 * @return		TeamPlayers $object
	 * @access		public
	 * @static
	 */
	public static function getInstance() 
    {
        if ( ! isset( self::$instance ) )
        {
            $c = __CLASS__;
            self::$instance = new $c;
        }
	    return self::$instance;
    }
	/**
	 * Handles a request and instantiates the controller
	 *
	 * @param		array $controllers
	 * @return		void
	 * @access		public
	 */
	public function respond( $controllers )
	{
	    /*
	     * Determine which controller should be instantiated to handle this request
	     */
	    $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? $_SERVER['REQUEST_URI'] : "/";
	    $request_uri = explode( "?", $request_uri, 2 );
	    $request_uri = $request_uri[0];
	    self::$request_uri = $request_uri;
	    $request_uri_stack = explode( "/", $request_uri );
	    $request_uri_stack_temp = array();
	    foreach ( $request_uri_stack as $request_uri_component )
	    {
	        if ( ! empty( $request_uri_component ) )
	        {
	            $request_uri_stack_temp[] = $request_uri_component;
	        }
	    }
	    $request_uri_stack = $request_uri_stack_temp;
	    $uri_to_controller = array();
	    foreach ( $controllers as $controller => $uris )
	    {
	        foreach ( $uris as $uri )
	        {
	            $uri_to_controller[$uri] = $controller;
	        } 
	    }
	    uksort( $uri_to_controller, array( $this, 'sortByURIElementCount' ) );
	    $uri_to_controller = array_reverse( $uri_to_controller );
	    /*
	     * Append URI parts until the deepest URI match is found
	     */
	    $request_uri_match_stack = array( "/" );
	    $request_uri_match = "";
	    foreach ( $request_uri_stack as $request_uri_component )
	    {
	        if ( isset( $uri_to_controller[$request_uri_match . "/" . $request_uri_component . "/"] ) )
	        {
	            if ( substr( $request_uri_match, -1 ) != "/" )
	            {
	                $request_uri_match .= "/";
	            }
	            $request_uri_match .= $request_uri_component;
	            $request_uri_match_stack[] = $request_uri_component;
	        }
	        else if ( isset( $uri_to_controller[$request_uri_match . "/" . $request_uri_component] ) )
	        {
	            if ( substr( $request_uri_match, -1 ) != "/" )
	            {
	                $request_uri_match .= "/";
	            }
	            $request_uri_match .= $request_uri_component;
	            $request_uri_match_stack[] = $request_uri_component;
	        }
	    }
	    if ( $request_uri_match == "" )
	    {
	        $request_uri_match = "/";
	    }
	    if ( isset( $uri_to_controller[$request_uri_match . "/"] ) )
	    {
	        $controller = $uri_to_controller[$request_uri_match . "/"];
	    }
	    else if ( isset( $uri_to_controller[$request_uri_match] ) )
	    {
	        $controller = $uri_to_controller[$request_uri_match];
	    }
	    else
	    {
	        $controller = "Controller";
	    }
	    $request_uri_remaining_stack = array_values( array_diff( $request_uri_stack, $request_uri_match_stack ) );
	    self::$stack = $request_uri_remaining_stack;
	    if ( $controller != "Controller" )
	    {
	        require $controller . ".class.php";
	    }
	    $controller = "\TeamPlayers\\" . $controller;
	    self::$controller = new $controller();
	}
	/**
	 * usort callback function for sorting an array by URI element count
	 *
	 * @param       mixed $a
	 * @param       mixed $b
	 * @return		int
	 * @access		public
	 * @static
	 */
	public static function sortByURIElementCount( $a, $b )
	{
	    if ( $a == $b )
	    {
	        return 0;
	    }
	    return substr_count( $a, "/" ) > substr_count( $b, "/" ) ? 1 : -1;
	}
	/**
	 * Returns a RFC 4211 v4 Universally Unique Identifier
	 *
	 * @return		string
	 * @access		public
	 * @static
	 */
	public static function uuid()
	{
	    return sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
	    
	    	    // 32 bits for "time_low"
	            mt_rand(0, 0xffff), mt_rand(0, 0xffff),
	    	
	            // 16 bits for "time_mid"
	            mt_rand(0, 0xffff),
	    
	            // 16 bits for "time_hi_and_version",
	    	    // four most significant bits holds version number 4
	            mt_rand(0, 0x0fff) | 0x4000,
	    	
	            // 16 bits, 8 bits for "clk_seq_hi_res",
	            // 8 bits for "clk_seq_low",
	            // two most significant bits holds zero and one for variant DCE1.1
	            mt_rand(0, 0x3fff) | 0x8000,
	    	
	            // 48 bits for "node"
	            mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
	    );
    }
    /**
     * Prevents instances from being cloned
     *
     * @return		void
     * @access		public
     */
    public function __clone()
	{
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }
}
?>
